package utsc.apps.utschedule.ui.activities;

import java.util.Calendar;

import utsc.apps.utschedule.R;
import utsc.apps.utschedule.UTSCheduleApp;
import utsc.apps.utschedule.classes.Course;
import utsc.apps.utschedule.classes.Timetable;
import utsc.apps.utschedule.ui.MessageDialogFragment;
import utsc.apps.utschedule.ui.MyColorPickerDialogFragment;
import utsc.apps.utschedule.ui.MyColorPickerDialogFragment.ChangeColorCellViewListener;
import utsc.apps.utschedule.ui.MyTimePickerDialogFragment;
import utsc.apps.utschedule.ui.interfaces.TimetableActivity;
import utsc.apps.utschedule.util.AppUtils;
import utsc.apps.utschedule.util.GenericActionModeCallback;
import utsc.apps.utschedule.util.TimetableHelper;
import utsc.apps.utschedule.util.Validator;
import utsc.apps.utschedule.util.database.DatabaseManager;
import utsc.apps.utschedule.widget.ColorCellView;
import android.app.Activity;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.FilterQueryProvider;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;

/**
 * This is a form liked activity which can be used for adding new courses or
 * edit courses.
 * 
 */
public class CourseFormActivity extends GenericFormActivity<Course> implements
		GenericActionModeCallback.OnMenuItemClickedListener, OnTimeSetListener,
		ChangeColorCellViewListener,OnClickListener,OnSeekBarChangeListener{
	public static final String TAG="CourseFormActivity";
	//private ActionMode _actionMode;
	private AutoCompleteTextView _txtCourseCode;
	private EditText _txtShorttitle;
	private EditText _txtSection;
	private EditText _txtStartTime;
	private EditText _txtEndTime;
	private RadioGroup _radioGrpTutorial;
	private TextView _txtOddweeks;
	private SeekBar _seekbarOddWeeks;
	private Spinner _spinnerWeekday;
	private EditText _txtLocation;
	private EditText _txtInstructor;
	private RadioGroup _radioGrpWeight;
	private int defaultHour=8;
	private EditText _currentEditingTimeView;
	private ColorCellView _colorCourse;
	private Course _course;
	private final Validator _validator=Validator.newInstance(TAG+" Validator");
	private boolean _requestResult=false;
	private int _courseID=-1;
	private Course _parentCourse;
	private SimpleCursorAdapter _courseCodeAdapter;
	
	//used to retrieve form values after orientation changed
	private static final String SELECTED_COLOR_KEY="colorPickerColor";
	private static final String SELECTED_STARTTIME_KEY="startTime";
	private static final String SELECTED_ENDTIME_KEY="endTime";
	
	private static final String[] FROM_COLS = new String[] {
		Course.COURSE_CODE};
	// Specify the corresponding layout elements where we want the columns to go
	private static final int[] TO_COLS = new int[] { android.R.id.text1};
	private static final String[] PARENT_COURSE_COLS={Course.COURSE_ID+" as _id ",Course.COURSE_CODE};
  	
	/**
	 * The query provider to query the database for a list of matched courses 
	 */
	private FilterQueryProvider _queryProvider=new FilterQueryProvider() {
		@Override
		public Cursor runQuery(CharSequence constraint) {
			return queryParentCourse(constraint);
		}
	};
	
	/**
	 * Takes the input constraint to perform a query to database.
	 * @param constraint -the input constraint
	 * @return -a cursor of the query result
	 */
	private Cursor queryParentCourse(CharSequence constraint) {
		final DatabaseManager dbManager=DatabaseManager.getInstance(CourseFormActivity.this);
	      Timetable t=dbManager.getCurrentActiveTimetable();
	      int timetableID=0;
	      
	      if (t!=null) {
	    	  timetableID=t.get_timetableID();
	      }
	      String query=null;
	      if (constraint==null) {
			query="";
	      }else {
			query=constraint.toString();
	      }
	      Cursor c=dbManager.queryParentCourse(query, timetableID, PARENT_COURSE_COLS);
	      
	      return c;
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		//get the invoked intent
		Intent requestIntent=getIntent();
		_requestCode=requestIntent.getIntExtra("RequestCode", -1);
		_requestResult=requestIntent.getBooleanExtra("RequestResult", false);
		//setup the resources
		setupBasicResources();
		
		//based on the request code
		//we perform different task
		switch (_requestCode) {
			case TimetableActivity.RESULT_NEW_COURSE:
				//add course
				getSupportActionBar().setTitle("Add Course");
				String action=requestIntent.getAction();
				if (action!=null&& action.equals(Intent.ACTION_VIEW)) {
					setupResourcesForUpdate(requestIntent);
				}else {
					setupResourcesForNew(requestIntent);
				}
				
				break;
			case TimetableActivity.RESULT_UPDATE_COURSE:
				getSupportActionBar().setTitle("Edit Course");
				setupResourcesForUpdate(requestIntent);
				break;
			default:
				break;
		}
		
		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
		//setup the course code input hit
		_courseCodeAdapter=new SimpleCursorAdapter(this, android.R.layout.simple_dropdown_item_1line, null, FROM_COLS, TO_COLS, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
		_courseCodeAdapter
				.setCursorToStringConverter(new CursorToStringConverter() {
					@Override
					public CharSequence convertToString(Cursor cursor) {
						final int columnIndex = cursor
								.getColumnIndexOrThrow(Course.COURSE_CODE);
						final String str = cursor.getString(columnIndex);
						return str;
					}
				});
		_courseCodeAdapter.setFilterQueryProvider(_queryProvider);
		
		_txtCourseCode.setAdapter(_courseCodeAdapter);
		_txtCourseCode.setThreshold(0);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}
	
	@Override
	protected void setupBasicResources() {
		SharedPreferences settings=PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		defaultHour=Integer.parseInt(settings.getString("start_hour", "8"));
		setContentView(R.layout.activity_course_form);
		_txtCourseCode=(AutoCompleteTextView) findViewById(R.id.frm_txt_coursecode);
		_txtShorttitle=(EditText) findViewById(R.id.frm_txt_shorttitle);
		_txtStartTime=(EditText) findViewById(R.id.frm_txt_starttime);
		_txtEndTime=(EditText) findViewById(R.id.frm_txt_endtime);
		_spinnerWeekday=(Spinner) findViewById(R.id.frm_spinner_weekday);
		_txtLocation=(EditText) findViewById(R.id.frm_txt_location);
		_txtInstructor=(EditText) findViewById(R.id.frm_txt_instructor);
		_colorCourse=(ColorCellView) findViewById(R.id.frm_course_color_cell);
		_txtSection=(EditText) findViewById(R.id.frm_txt_section);
		_radioGrpTutorial=(RadioGroup) findViewById(R.id.frm_radiogrp_tutorial);
		_txtOddweeks=(TextView) findViewById(R.id.frm_txt_oddweeks);
		_seekbarOddWeeks=(SeekBar) findViewById(R.id.frm_seekbar_oddweeks);
		_radioGrpWeight=(RadioGroup)findViewById(R.id.frm_radiogrp_weight);
		_txtStartTime.setOnClickListener(this);

		_txtEndTime.setOnClickListener(this);
		//assign a text changed listener
		_txtEndTime.addTextChangedListener(new TextWatcher() {
			
			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count) {
			}
			
			@Override
			public void beforeTextChanged(CharSequence s, int start, int count, int after) {
			}
			
			@Override
			public void afterTextChanged(Editable s) {
				final Calendar currentStartTime=TimetableHelper.convertFromDateTimeString(_txtStartTime.getText().toString(), TimetableHelper.TYPE_TIME);
				final Calendar currentEndTime=TimetableHelper.convertFromDateTimeString(s.toString(), TimetableHelper.TYPE_TIME);
				//show an error message when the selected time is not a valid end time
				if (!currentEndTime.after(currentStartTime)) {
					Toast.makeText(CourseFormActivity.this, "End time cannot set before the Start time.", Toast.LENGTH_LONG).show();
					showTimePickerDialog(currentEndTime, false, CourseFormActivity.this);
				}else {
					//otherwise, remove the dialog from fragment stack
					removeFragment(MyTimePickerDialogFragment.TAG).commit();
				}
			}
		});
		_colorCourse.setOnClickListener(this);
		_seekbarOddWeeks.setOnSeekBarChangeListener(this);
	}
	
	@Override
	protected void setupResourcesForNew(Intent requestIntent){
		//retrieve data saved right before configuration changed 
		final Object savedData=getLastCustomNonConfigurationInstance();
		final int selectedHour=requestIntent.getIntExtra("SelectedHour", defaultHour);
		int weekdayIndex=requestIntent.getIntExtra("SelectedWeekday", 1);
		int color=Color.WHITE;
		String defaultStartTime=TimetableHelper.getHourString(selectedHour,0);
		String defaultEndTime=TimetableHelper.getHourString(selectedHour+1,0);
		String defaultOddweeks="1";
		//if we found something, set them to the form
		if (savedData!=null) {
			final Bundle b=(Bundle) savedData;
			color=b.getInt(SELECTED_COLOR_KEY, Color.WHITE);
			defaultStartTime=b.getString(SELECTED_STARTTIME_KEY);
			defaultEndTime=b.getString(SELECTED_ENDTIME_KEY);
		}
		
		_txtStartTime.setText(defaultStartTime);
		_txtEndTime.setText(defaultEndTime);
		
		_spinnerWeekday.setSelection(weekdayIndex);
		
		_colorCourse.set_currentColor(color);
		
		_txtOddweeks.setText(defaultOddweeks);
		
	}
	
	/**
	 * This is a helper method to handle edit time event.
	 * @param textView - the edit text which holds the time string
	 */
	private void onEditTime(EditText textView){
		_currentEditingTimeView=textView;
		AppUtils.hideKeyBoard(CourseFormActivity.this, textView);
		final Calendar currentTimeSelection=TimetableHelper.convertFromDateTimeString(textView.getText().toString(), TimetableHelper.TYPE_TIME);
		if (currentTimeSelection!=null) {
			showTimePickerDialog(currentTimeSelection, false, this);
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		if (_requestCode==TimetableActivity.RESULT_NEW_COURSE) {
			getSupportMenuInflater().inflate(R.menu.add_cancel_menu, menu);
		}else {
			getSupportMenuInflater().inflate(R.menu.update_cancel_menu_items, menu);
		}
		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		onMenuItemClicked(item);
		return true;
	}
	@Override
	public void onActionModeFinished(ActionMode mode) {
		super.onActionModeFinished(mode);
		setResult(Activity.RESULT_CANCELED);
		finish();
	}
	@Override
	public void onMenuItemClicked(MenuItem item) {
		int id = item.getItemId();
		if (id != R.id.cancel && id!=android.R.id.home) {
			String errorTitle = AppUtils.ERROR_TITLE_COURSE_ADD;
			String successMsg = AppUtils.TOAST_ADD_COURSE_SUCCESSFULLY_STRING;
			if (id == R.id.update) {
				errorTitle = AppUtils.ERROR_TITLE_COURSE_UPDATE;
				successMsg = AppUtils.TOAST_UPDATE_COURSE_SUCCESSFULLY_STRING;
			}
			if (_course == null) {
				_course = new Course();
			}
			setupCourse();
			//form validation
			if (validate(_course)) {
				//validation is pass
				UTSCheduleApp app = (UTSCheduleApp) getApplication();
				final Timetable currentTimetable = app
						.get_currentActiveTimetable();
				// get the current active timetable
				if (currentTimetable != null) {
					app.refreshCurrentTimetable();
					_course.set_timetable(currentTimetable);
					_parentCourse=DatabaseManager.getInstance(this).queryParentCourse(_txtCourseCode.getText().toString(), currentTimetable.get_timetableID());
					//if parent course is null,
					//set this course as its parent course
					if (_parentCourse==null) {
						_course.set_parentCourse(new Course(-1));
						DatabaseManager.getInstance(this).saveCourse(_course);
						_course.set_parentCourse(_course);
					}else {
						_course.set_parentCourse(_parentCourse);
					}
					DatabaseManager.getInstance(this).saveCourse(_course);
					//refresh the active course list
					currentTimetable.refreshCourseList();
				}
			} else {
				showDialogFragment(MessageDialogFragment.newInstance(
						errorTitle, _validator.get_errorMessages()),
						MessageDialogFragment.TAG);
				return;
			}
			Toast.makeText(this, successMsg, Toast.LENGTH_SHORT).show();

			if (_requestResult) {
				Intent resultIntent = new Intent();
				resultIntent.putExtra("CourseFormResult", _courseID);
				if (id==R.id.add) {
					resultIntent.putExtras(_course.getCourseIntent());
				}
				setResult(Activity.RESULT_OK, resultIntent);
			}
			
			finish();

		} else {
			if (_requestCode==TimetableActivity.RESULT_NEW_COURSE) {
				Toast.makeText(this, AppUtils.TOAST_ADD_COURSE_CANCELLED_STRING,
						Toast.LENGTH_SHORT).show();
			}else {
				Toast.makeText(this, AppUtils.TOAST_UPDATE_COURSE_CANCELLED_STRING,
						Toast.LENGTH_SHORT).show();
			}
			finish();
		}
		
	}

	@Override
	public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
		view.setCurrentHour(hourOfDay);
		view.setCurrentMinute(minute);
		_currentEditingTimeView.setText(TimetableHelper.getHourString(hourOfDay, minute));
	}
	
	@Override
	public Object onRetainCustomNonConfigurationInstance() {
		Bundle b=new Bundle();
		b.putInt(SELECTED_COLOR_KEY, _colorCourse!=null?_colorCourse.get_currentColor():Color.WHITE);
		b.putString(SELECTED_STARTTIME_KEY, _txtStartTime.getText().toString());
		b.putString(SELECTED_ENDTIME_KEY, _txtEndTime.getText().toString());
		b.putInt(CourseDetailActivity.REQUEST_COURSE_KEY, _courseID);
		return b;
	}

	@Override
	public void onFinishColorPickerDialog(int color) {
		if (_colorCourse!=null) {
			_colorCourse.set_currentColor(color);
		}
	}

	@Override
	public void onClick(View v) {
		int id=v.getId();
		switch (id) {
		case R.id.frm_txt_starttime:
			onEditTime(_txtStartTime);
			break;
		case R.id.frm_txt_endtime:
			onEditTime(_txtEndTime);
			break;
		case R.id.frm_course_color_cell:
			final MyColorPickerDialogFragment colorFragment=MyColorPickerDialogFragment.newInstance(_colorCourse.get_currentColor());
			colorFragment.show(getSupportFragmentManager(), MyColorPickerDialogFragment.TAG);
			break;
		default:
			break;
		}
	}

	@Override
	protected boolean validate(Course object) {
		_validator.reset();
		_validator.checkNull(object.get_courseCode(), AppUtils.ERROR_MESSAGE_COURSE_COURSECODE);
		_validator.checkNull(object.get_location(), AppUtils.ERROR_MESSAGE_COURSE_LOCATION);
		_validator.checkTimeInterval(object.get_startTime(), object.get_endTime(), 1, 0, AppUtils.ERROR_MESSAGE_COURSE_TIME);
		if (_validator.get_errorMessages()==null) {
			return true;
		}
		return false;
	}

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		_txtOddweeks.setText(Integer.toString(progress));
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
	}

	@Override
	protected void setupResourcesForUpdate(Intent requestIntent) {
		if (requestIntent!=null) {
			//check the intent to see if it is coming from online search results
			//if yes, we setup the resources accordingly
			if (_requestCode==TimetableActivity.RESULT_NEW_COURSE && requestIntent.getAction().equals(Intent.ACTION_VIEW)) {
				_course=new Course(requestIntent);
				if (_course.get_startTime()==0 && _course.get_endTime()==0) {
					_course.set_startTime(TimetableHelper.getPredefinedTime(defaultHour, Calendar.HOUR_OF_DAY));
					_course.set_endTime(TimetableHelper.getPredefinedTime(defaultHour+1, Calendar.HOUR_OF_DAY));
				}
			}else {
				_courseID= requestIntent.getIntExtra(CourseDetailActivity.REQUEST_COURSE_KEY,-1);
				_course=DatabaseManager.getInstance(getApplicationContext()).getCourse(_courseID);
			}
			
			final Object savedData=getLastCustomNonConfigurationInstance();
			int weekdayIndex=_course.get_day();
			int color=_course.get_color();
			String defaultStartTime=TimetableHelper.getFormattedString(_course.get_startTime(), TimetableHelper.TYPE_TIME);
			String defaultEndTime=TimetableHelper.getFormattedString(_course.get_endTime(), TimetableHelper.TYPE_TIME);
			String defaultOddweeks=Integer.toString(_course.get_oddWeeks());
			//if we found something, set them to the form
			if (savedData!=null) {
				final Bundle b=(Bundle) savedData; 
				color=b.getInt(SELECTED_COLOR_KEY, Color.WHITE);
				defaultStartTime=b.getString(SELECTED_STARTTIME_KEY);
				defaultEndTime=b.getString(SELECTED_ENDTIME_KEY);
			}
			_txtCourseCode.setText(_course.get_courseCode());
			_txtShorttitle.setText(_course.get_shortName());
			_txtSection.setText(_course.get_section());
			_radioGrpTutorial.check(_course.is_tutorial()?R.id.frm_radio_tutorial_yes:R.id.frm_radio_tutorial_no);
			_radioGrpWeight.check(_course.get_weight()>0.5?R.id.frm_radio_whole:R.id.frm_radio_half);
			_txtStartTime.setText(defaultStartTime);
			_txtEndTime.setText(defaultEndTime);
			
			_spinnerWeekday.setSelection(weekdayIndex);
			
			_colorCourse.set_currentColor(color);
			
			_txtOddweeks.setText(defaultOddweeks);
			_txtLocation.setText(_course.get_location());
			_txtInstructor.setText(_course.get_instructor());
		}else {
			setupResourcesForNew(requestIntent);
		}
		
	}
	
	/**
	 * Setup the {@link Course course} object by collecting all the data from the form.
	 */
	private void setupCourse() {
		_course.set_color(_colorCourse.get_currentColor());
		_course.set_courseCode(_txtCourseCode.getText().toString());
		_course.set_startTime(TimetableHelper.getTimeFromString(_txtStartTime.getText().toString()));
		_course.set_endTime(TimetableHelper.getTimeFromString(_txtEndTime.getText().toString()));
		_course.set_day(_spinnerWeekday.getSelectedItemPosition());
		_course.set_location(_txtLocation.getText().toString());
		_course.set_instructor(_txtInstructor.getText().toString());
		_course.set_shortName(_txtShorttitle.getText().toString());
		_course.set_tutorial(_radioGrpTutorial.getCheckedRadioButtonId()==R.id.frm_radio_tutorial_yes);
		_course.set_oddWeeks(_seekbarOddWeeks.getProgress());
		_course.set_section(_txtSection.getText().toString());
		_course.set_weight(_radioGrpWeight.getCheckedRadioButtonId()==R.id.frm_radio_whole?1.0:0.5);
		
	}
	
}
